题目描述
一个整型数组 $nums$ 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
1 | 输入:nums = [4,1,4,6] |
示例 2:
1 | 输入:nums = [1,2,10,4,1,4,3,3] |
限制:
- $2 <= nums.length <= 10000$
算法
(位运算,异或) $O(n)$
首先我们知道求数组中只出现一次的一个数字的求法,因为除了这个数其他数都出现了两次,所以将所有数异或起来的结果就是答案。
这道题目要求的是只出现一次的两个数字,我们需要想办法把它拆解成第一类问题
假设两个数字为 $x、y$
- 先将所有数异或起来的结果记为
sum = x ^ y
,因为其他数字都出现两次,它们异或的结果是 $0$ - 由于
x != y
则 $x$ 和 $y$ 不全为 $0$,所以 $sum$ 必不为 $0$,那么 $sum$ 的二进制表示中肯定有 $1$,且对于为 $1$ 位,$x$ 和 $y$ 必然其中一个为 $1$,另一个为 $0$,否则异或的结果当前位不可能为 $1$,按照 $sum$ 的二进制表示中最后一个 $1$(假设是第 k 位) 所有数划分为两个集合,一个集合中第 $k$ 位全为 $1$,另一个集合中第 $k$ 位全为 $0$,且 $x$ 和 $y$ 不在同一个集合 - 此时问题就转换成了求两个「数组中只出现一次的一个数字」,对两个集合分别异或起来,得到的就是 $x$ 和 $y$
优化:只求一个集合的异或结果可以得到一个数 $first (= x / y)$,而已知
sum = x ^ y
,则 $first$ ^ $sum$ 就是另一个数
时间复杂度
考虑最长时间就是遍历数组所花费的时间,时间复杂度为 $O(n)$。
空间复杂度
$O(1)$
C++ 代码
1 | class Solution { |